Skip to content

action handler: reactive dispatch + native executor + hard-gate uplink + B2-lift (capabilities)#122

Merged
AdaWorldAPI merged 3 commits into
mainfrom
claude/actionhandler-dispatch-core
Jun 24, 2026
Merged

action handler: reactive dispatch + native executor + hard-gate uplink + B2-lift (capabilities)#122
AdaWorldAPI merged 3 commits into
mainfrom
claude/actionhandler-dispatch-core

Conversation

@AdaWorldAPI

@AdaWorldAPI AdaWorldAPI commented Jun 24, 2026

Copy link
Copy Markdown
Owner

What

Continues the arago ActionHandler runtime toward a live drop-in. OGAR now runs a real command end-to-end, behind a hard authorization gate, from a real REST registration.

1. Reactive dispatch + the B1 executor seam (ogar-from-schema/action_ws.rs)

  • CapabilityExecutor trait — the seam where a command runner plugs in (the only piece that does real I/O). The RBAC/guard gate (commit_via) is owned downstream, so the producer crate stays lance-graph-free.
  • handle_submit(msg, def, signature, executor) — validate id → ack-or-nack → bind params → execute → sendActionResult. Rejects invalid id / unknown capability before ack; reports post-ack bind/exec failure as {"error":…} in the result.
  • 5 tests with a mock executor.

2. New crate ogar-action-handler — the runtime (B1 native target)

  • NativeCommandExecutor runs an ExecuteCommand's command via a local POSIX shell, returning output/stderr/exitcode. full_dispatch_runs_a_real_command: echo running end-to-end → {"output":"running",…}.

3. The hard-gate uplink (documented here; code in rs-graph-llm)

The executor is wired behind the hard gate in rs-graph-llm's new graph-flow-action-ogar seam (GatedOgarHandler / run_gated): dispatch_via's cold floor (commit_via: RBAC ∧ state-guard ∧ MUL) lands before the OGAR executor's handle. Structural proof — take_result() is None whenever the gate refused, so an unauthorized (Denied) or MUL-blocked (Escalated) action never reaches the executor. OGAR owns the executor; rs-graph-llm owns the gate; the seam joins them without OGAR taking a lance-graph dep. Recorded as the B1-uplink scorecard row + D-ACTIONHANDLER-UPLINK + E-ACTIONHANDLER-UPLINK.

4. B2-lift — REST registration instance lift, capabilities (ogar-from-schema/registration.rs + ogar-action-handler)

The OGIT ontology declares only that a capability has param slots; the concrete (name, mandatory, default) tuples live in a deployed handler's config. B2-lift reads them from the live REST view, so the two halves compose.

  • Producer stays parser-free. registration.rs defines the typed REST DTOs (RegisteredCapability / ModelFilter, Deserialize behind the serde feature) + the pure lift (lift_registration → ConcreteCapability with concrete ActionParam[]; model_filter_to_guard: ModelFilter{Var,Mode,Value}StateGuard, field-for-field). No serde_json, no I/O.
  • Runtime owns the read. ogar-action-handler::parse_capabilities does the serde_json read of a GET /capabilities body. rest_registration_lifts_binds_and_runs proves it end-to-end: real JSON → lift → bind_parametersNativeCommandExecutor runs the command. Same producer-defines-types / runtime-does-I/O split the whole crate family keeps.

Parity state

Contract, lifecycle, protocol binding, reactive dispatch, a working native executor, the hard authorization gate, and the capabilities REST instance lift are all OGAR-native and tested. What remains for a live drop-in of the Python daemon: B2-transport (the WebSocket loop — all message shapes/auth pinned), the B2-lift applicabilities envelope (GET /applicabilities JSON read; the ModelFilter→StateGuard lift is done), and the non-native executor targets (SSH/REST). Each is transport/parser/runner glue over existing types — no missing IR.

Tests

54 green across the two crates (48 ogar-from-schema + 6 ogar-action-handler + doctest), clippy-clean on new code. Docs: ARAGO-ACTIONHANDLER-PARITY scorecard + D-ACTIONHANDLER-{PARITY,UPLINK,B2LIFT} ledger rows + epiphanies.

Sources: github.com/arago/ActionHandlers, arago/python-hiro-stonebranch-actionhandler, and the HIRO 7 Action API spec.

🤖 Generated with Claude Code

…runs a command

Continues the arago ActionHandler runtime toward a live drop-in. Two bricks:

1. Reactive dispatch + the B1 executor seam (ogar-from-schema/action_ws.rs):
   - CapabilityExecutor trait — the seam where a runner plugs in (the only piece
     that does real I/O); the RBAC/guard gate (commit_via) is owned by the impl
     downstream, keeping the producer crate lance-graph-free.
   - handle_submit(msg, def, signature, executor) — the whole handler reaction:
     validate id -> ack-or-nack -> bind params -> execute -> sendActionResult.
     Rejects invalid id / unknown capability before ack; reports post-ack
     bind/exec failure as {"error":...} in the result (documented OGAR convention).
   - 5 tests with a mock executor (accept+run, unknown-capability nack, invalid-id
     nack, bind-failure, executor-failure).

2. New crate ogar-action-handler — the runtime (B1 native target):
   - NativeCommandExecutor runs an ExecuteCommand capability's `command` via a
     local POSIX shell, returns output/stderr/exitcode as resultParameters (the
     arago SSH-handler shape, minus SSH). Trust model documented (gate is upstream).
   - full_dispatch_runs_a_real_command: handle_submit + NativeCommandExecutor run
     `echo running` end-to-end -> {"output":"running",...}. OGAR runs a command here.
   - SSH/REST/WinRM targets follow the same trait (rs-graph-llm graph-flow-action
     for production); this is the reference native impl.

48 tests green across the two crates (43 + 5 + doctest), clippy-clean on new code.

Docs: ARAGO-ACTIONHANDLER-PARITY scorecard (dispatch + native exec SHIPPED;
remaining B2-transport / B2-lift / non-native executors); D-ACTIONHANDLER-PARITY
row. Also scrubbed the internal dev-portal host from the doc (neutral spec refs).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYvNjD8M8LMNYbRy3gq2FP
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

claude added 2 commits June 24, 2026 07:44
The hard gate is now wired to the executor in rs-graph-llm's new
`graph-flow-action-ogar` seam crate (`GatedOgarHandler` / `run_gated`):
`dispatch_via`'s cold floor (`commit_via`: RBAC ∧ state-guard ∧ MUL) lands
before the OGAR `CapabilityExecutor` runs. The structural proof is a negative —
`take_result()` is `None` whenever the gate refused, so an unauthorized
(`Denied`) or MUL-blocked (`Escalated`) action never reaches the executor.
OGAR owns the executor; rs-graph-llm owns the gate; the seam crate joins them
without OGAR taking a `lance-graph` dep.

- ARAGO-ACTIONHANDLER-PARITY: new B1-uplink §3 bullet + scorecard row (SHIPPED),
  verdict note (gate wired to executor), cross-ref to the seam crate.
- DISCOVERY-MAP: new D-ACTIONHANDLER-UPLINK row (G / CODED), cross-ref
  D-ACTIONHANDLER-PARITY (append-only; existing row untouched).
- EPIPHANIES: E-ACTIONHANDLER-UPLINK (FINDING) — the load-bearing proof is the
  negative test; the coupling lives in the seam, not in graph-flow-action.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYvNjD8M8LMNYbRy3gq2FP
Parse a deployed handler's REST registration into the concrete OGAR signatures
the *schema* half cannot supply. The OGIT ontology declares only that a
capability has mandatoryParameters/optionalParameters slots; the concrete
(name, mandatory, default) tuples live in a deployed handler's config. B2-lift
reads them from the live REST view, so the two halves compose: schema lift gives
the contract shape, instance lift gives the deployed values.

Producer stays parser-free (the crate-family split):
- ogar-from-schema/src/registration.rs — typed REST DTOs (RegisteredCapability /
  RegisteredParam / ModelFilter, Deserialize behind the existing `serde` feature)
  + the pure lift: lift_registration -> ConcreteCapability (concrete ActionParam[]),
  and model_filter_to_guard (arago ModelFilter{Var,Mode,Value} -> StateGuard,
  field-for-field). No serde_json, no I/O. 5 tests incl. the lifted signature
  driving action_ws::bind_parameters.
- ogar-action-handler — the runtime owns I/O: parse_capabilities does the
  serde_json read of a GET /capabilities body. Proven end-to-end by
  rest_registration_lifts_binds_and_runs (real JSON -> lift -> bind -> the
  NativeCommandExecutor runs the command).

Same producer-defines-types / runtime-does-I/O split the whole crate family
keeps: ogar-from-schema gains a REST front-end without gaining a parser dep.

Remaining for full B2-lift: the GET /applicabilities MapOfApplicabilities JSON
envelope read (the ModelFilter->StateGuard lift is already shipped).

Docs: ARAGO-ACTIONHANDLER-PARITY (B2-lift §3 bullet + two scorecard rows +
verdict + cross-refs), D-ACTIONHANDLER-B2LIFT discovery row, E-ACTIONHANDLER-B2LIFT
epiphany (the parser-free producer / runtime-does-the-read split).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYvNjD8M8LMNYbRy3gq2FP
@AdaWorldAPI AdaWorldAPI changed the title action handler: reactive dispatch (B1 seam) + native executor — OGAR runs a command action handler: reactive dispatch + native executor + hard-gate uplink + B2-lift (capabilities) Jun 24, 2026
@AdaWorldAPI AdaWorldAPI merged commit 048a2ce into main Jun 24, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants